package team.star.werespos.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import team.star.werespos.config.shiro.CurrPrincipal;
import team.star.werespos.exception.GlobalException;
import team.star.werespos.mapper.UserMapper;
import team.star.werespos.mapper.UserRoleMapper;
import team.star.werespos.model.entity.Role;
import team.star.werespos.model.entity.User;
import team.star.werespos.model.entity.UserRole;
import team.star.werespos.model.enums.CodeMsgEnum;
import team.star.werespos.service.UserService;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * UserServiceImpl class<br/>
 *
 * @author hdonghong
 * @since  2018/04/30
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    public User insertOne(User user) {
        // 非空检查
        Preconditions.checkNotNull(user, "user is null!");

        user.setSalt(getRandom(user.getPassword(), System.currentTimeMillis() + "hdh"));
        user.setPassword(getRandom(user.getPassword(), user.getSalt()));
        // 新增
        Integer result = userMapper.insert(user);
        if (result == 0) {
            log.error("【新增用户】失败！result = [{}], user = [{}]", result, user);
            throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
        }
        Set<Role> roles = user.getRoles();
        if (!CollectionUtils.isEmpty(roles)) {
            UserRole userRole = new UserRole();
            userRole.setUid(user.getUid());
            roles.forEach(role -> userRoleMapper.insert(
                    userRole.setRid(role.getRid())
            ));
        }
        return user;
    }

    @Override
    public List<User> listUsers() {
        return userMapper.listUsers();
    }

    @Override
    public void updateById(User user) {
        User userFromDb = getOne(user.getUid());
        // 如果要修改密码
        if (user.getPassword() != null && user.getPassword().length() < 16 && user.getPassword().length() > 1) {
            user.setPassword(getRandom(user.getPassword(), userFromDb.getSalt()));
            Integer result = userMapper.updateById(user);
            if (result == 0) {
                log.error("【修改用户】失败！result = [{}], user = [{}]",
                        result, user);
                throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
            }
        }

        Set<Role> rolesFromDB = userFromDb.getRoles();
        Set<Role> roles = user.getRoles();
        // 没更改权限则结束执行
        if (rolesFromDB.equals(roles)) {
            return;
        }
        rolesFromDB.forEach(r -> userRoleMapper.delete(new QueryWrapper<UserRole>()
                .eq("rid", r.getRid())
                .eq("uid", user.getUid()))
        );
        roles.forEach(r -> userRoleMapper.insert(
                new UserRole(user.getUid(), r.getRid()))
        );
    }

    @Override
    public void deleteById(User user) {
        Optional.ofNullable(userMapper.deleteById(user))
                .ifPresent(result -> {
                    if (result == 0) {
                        log.error("【删除用户】失败！result = [{}], user = [{}]",
                                result, user);
                        throw GlobalException.create(CodeMsgEnum.DATABASE_EXCEPTION);
                    }
                });
    }

    @Override
    public User findByUsername(String username) {
        return userMapper.findByUsername(username);
    }

    @Override
    public User getOne(int uid) {
        return userMapper.getUser(uid);
    }

    @Override
    public void updatePassword(String oldPwd, String newPwd) {
        User user = CurrPrincipal.get();
        String oldEncPwd = getRandom(oldPwd, user.getSalt());
        if (!Objects.equals(oldEncPwd, user.getPassword())) {
            throw GlobalException.create(CodeMsgEnum.PASSWORD_ERROR);
        }
        user.setPassword(getRandom(newPwd, user.getSalt()));
        userMapper.updateById(user);
    }

    /**
     * 返回随机串
     * @param source
     * @param salt
     * @return
     */
    private String getRandom(String source, String salt) {
        return new SimpleHash(
                "MD5", source, ByteSource.Util.bytes(salt), 1024).toString();
    }
}
